﻿using System;
using System.Collections.Generic;
using System.ServiceProcess;
using System.Timers;
using PSE.Framework.ErrorLogging;
using PSE.Updater.Client.Providers;
using PSE.Updater.Client.Providers.Updates;
using PSE.Updater.Common.Configurations.Monitor;
using PSE.Updater.Common.Providers;
using ConfigurationFile = PSE.Updater.Client.Providers.ConfigurationFile;
using Updates = PSE.Updater.Client.Providers.Updates;
using System.Reflection;
using System.Diagnostics;
using Microsoft.Win32;

namespace PSE.Updater.Monitor
{
    partial class MonitorService : ServiceBase
    {
        private const int CONST_MINUTES = 1;

        private Timer _scheduleTimer = null;
        private Timer _updatesTimer = null;
        private Timer _configurationFileTimer = null;

        public MonitorService()
        {
            InitializeComponent();
        }

        private void InitializeTimers()
        {
            var isScheduled = ScheduleExecutation.Instance.IsScheduled();

            if (!isScheduled)
            {
                MonitorConfigurationSection configurations = MonitorConfiguration.Instance.GetSection();
                foreach (MonitorConfigurationElement configuration in configurations.Providers)
                {
                    switch (configuration.Type)
                    {
                        case ProviderType.ConfigurationFile: InitializeConfigurationFileTimer(configuration.Interval);
                            break;
                        case ProviderType.Updates: InitializeUpdateTimer(configuration.Interval);
                            break;
                    }
                }
            }

            InitializeScheduleTimer(CONST_MINUTES.MinutesToMilliseconds());
        }

        private void InitializeTimer(ref Timer timer, double interval, Action action)
        {
            if (timer == null)
                timer = new Timer();

            timer.Interval = interval;
            timer.Elapsed += (sender, o) =>
            {
                try
                {
                    StopTimers();
                    action();
                }
                catch (Exception ex)
                {
                    ErrorLogger.WriteLog(LogType.Error, ex);
                }
                finally
                {
                    InitializeTimers();
                }
            };
            timer.Start();
        }

        private void InitializeUpdateTimer(double interval)
        {
            InitializeTimer(ref _updatesTimer, interval, ExecuteUpdates);
        }

        private void InitializeConfigurationFileTimer(double interval)
        {
            InitializeTimer(ref _configurationFileTimer, interval, ExecuteConfigurationFile);
        }

        private void InitializeScheduleTimer(double interval)
        {
            InitializeTimer(ref _scheduleTimer, interval, ExecuteScheduler);
        }

        private void StopTimers()
        {
            StopTimer(ref _updatesTimer);
            StopTimer(ref _configurationFileTimer);
            StopTimer(ref _scheduleTimer);
        }
        private void StopTimer(ref Timer timer)
        {
            if (timer != null)
            {
                timer.Enabled = false;
                timer.Stop();
                timer.Dispose();
                timer = null;
            }
        }

        private void ExecuteScheduler()
        {
            DateTime? date = ScheduleExecutation.Instance.GetDateTime();
            if (date.HasValue)
            {
                if (DateTime.Now >= date.Value)
                {
                    ExecuteUpdates();
                }
            }

        }
        private void ExecuteConfigurationFile()
        {
            UpdateBase update = new ConfigurationFile.Update();
            update.Initialize();
        }
        private void ExecuteUpdates()
        {
            string assemblyPath = Assembly.GetEntryAssembly().Location;
            string folder = System.IO.Path.GetDirectoryName(assemblyPath);
            string exe = "Updater.exe";
            string path = System.IO.Path.Combine(folder, exe);

            Process updaterProcess = null;
            try
            {
                updaterProcess = Process.Start(exe);
                updaterProcess.Kill();
            }
            catch { }
            PSE.Updater.Common.Util.Instance.ExecuteSystem(path, string.Empty, true);
        }

        [STAThread]
        protected override void OnStart(string[] args)
        {
            System.Threading.Thread.Sleep(8.SecondsToMilliseconds());

            RemoveSystrayInactivesIcons();

            bool updateOnWinStart = ScheduleExecutation.Instance.GetUpdateOnWinStart();
            if (updateOnWinStart)
                ExecuteUpdates();

            InitializeTimers();
        }

        //Bug do XP
        private void RemoveSystrayInactivesIcons()
        {
            try
            {
                List<string> keys = new List<string>();
                keys.Add(@"Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify"); //XP
                keys.Add(@"Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"); //Vista,7 e outros...

                foreach (string key in keys)
                {
                    RegistryKey trayNotify = Registry.CurrentUser.OpenSubKey(key, true);
                    if (trayNotify != null)
                    {
                        trayNotify.DeleteValue("IconStreams");
                        trayNotify.DeleteValue("PastIconsStream");
                    }
                }
            }
            catch{}
        }

        protected override void OnStop()
        {
            StopTimers();
        }
    }
}